﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Web;

namespace Emoney.F10.Common
{
    /// <summary>
    /// Author:		 喻旻
    /// Create date: 2011-07-22
    /// Description: 抓取网页数据
    /// Editer:马鹏飞
    /// Edit Date: 2011-08-17
    /// </summary>
    public class Client
    {
        private System.Text.Encoding encode = Encoding.GetEncoding("gb2312");
        private string method = "GET";

        /// <summary>
        /// GET方式提交，可指定字符集
        /// </summary>
        /// <param name="UrlString"></param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public string GetClientBySocket(string UrlString, System.Text.Encoding encode)
        {
            this.encode = encode;
            return GetClientBySocket(UrlString);
        }

        /// <summary>
        /// GET方式，默认字符集，本项目为gbk
        /// </summary>
        /// <param name="UrlString"></param>
        /// <returns></returns>
        public string GetClientBySocket(string UrlString)
        {
            try
            {
                byte[] data = GetData(UrlString);
                return encode.GetString(data);
            }
            catch 
            {
                return "";
            }
        }

        /// <summary>
        /// POST 方式提交
        /// </summary>
        /// <param name="url"></param>
        /// <param name="dic"></param>
        /// <returns></returns>
        public string UpdateData(string url, Dictionary<string, string> dic)
        {
            byte[] data = UpdateData(url, dic, "");
            return encode.GetString(data);
        }

        public byte[] UpdateData(string url, Dictionary<string, string> dic, string type)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var key in dic.Keys)
            {
                if (sb.Length != 0)
                {
                    sb.Append("&");
                }
                sb.Append(key + "=" + HttpUtility.UrlEncode(dic[key], encode));
            }
            method = "POST";
            return GetData(url, sb.ToString());
        }

        public byte[] GetData(string url)
        {
            return GetData(url, "");
        }

        private byte[] GetData(string UrlString, string updata)
        {
            string host;
            int port = 80;
            if (UrlString.StartsWith("http://"))
            {
                string temp = UrlString.Trim();
                temp = temp.Substring(7, temp.Length - 7);
                if (temp.IndexOf("/") == -1)
                {
                    host = temp;
                }
                else
                {
                    host = temp.Substring(0, temp.IndexOf("/"));
                }
                int portIndex = host.IndexOf(":");
                if (portIndex != -1)
                {
                    port = int.Parse(host.Substring(portIndex + 1));
                    host = host.Substring(0, portIndex);
                }
            }
            else
            {
                host = UrlString.Substring(0, UrlString.IndexOf("/"));
            }

            IPAddress[] ips = Dns.GetHostAddresses(host);
            IPAddress ip = ips[0];
            IPEndPoint serverhost = new IPEndPoint(ip, port);
            Socket clientSocket = null;
            try
            {
                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                clientSocket.Connect(serverhost);

                string httpReq = method + " " + UrlString + " HTTP/1.1\r\n";
                httpReq += "Host:" + host + "\r\n";
                httpReq += "Content-Type: application/x-www-form-urlencoded;Charset=" + encode.BodyName + "\r\n";
                if (method.ToUpper().Trim() == "POST")
                {
                    httpReq += "Content-length:" + updata.Length + "\r\n";
                }
                httpReq += "Connection: close\r\n\r\n";
                httpReq += updata;
                StringBuilder txtHTML = new StringBuilder();

                clientSocket.Send(encode.GetBytes(httpReq));
                Byte[] buffer = new byte[10240];
                int byteCount = clientSocket.Receive(buffer, buffer.Length, 0);
                List<byte> bLst = new List<byte>();
                AddByte(bLst, buffer, byteCount);
                while (byteCount > 0)
                {
                    byteCount = clientSocket.Receive(buffer, buffer.Length, 0);
                    AddByte(bLst, buffer, byteCount);

                }
                byte[] bbs = new byte[bLst.Count];
                for (int i = 0; i < bLst.Count; i++)
                {
                    bbs[i] = bLst[i];
                }
                //判断页面状态
                string strState = string.Empty;
                for (int i = 0; i < bbs.Length; i++)
                {
                    if (bbs[i] == '\r' && bbs[i + 1] == '\n')
                    {
                        strState = this.encode.GetString(bbs, 0, i);
                        break;
                    }
                }
                var ss = strState.Substring(strState.IndexOf(' ') + 1);
                if (ss != "200 OK")
                {
                    throw new Exception(ss);
                }
                int dataIndex = 0;
                for (int i = 0; i < bbs.Length; i++)
                {
                    if (bbs[i] == '\r' && bbs[i + 1] == '\n' && bbs[i + 2] == '\r' && bbs[i + 3] == '\n')
                    {
                        dataIndex = i + 4;
                        break;
                    }
                }
                string strHeaders = encode.GetString(bbs, 0, dataIndex);
                var dicHeaders = GetHeaders(strHeaders);
                int length=0;
                if (dicHeaders.ContainsKey("Content-Length"))
                {
                    length = int.Parse(dicHeaders["Content-Length"]);
                }
                else
                {
                    int dataIndex2 = dataIndex;
                    for (int i = dataIndex; i < bbs.Length; i++)
                    {
                        if (bbs[i] == '\r' && bbs[i + 1] == '\n')
                        {
                            dataIndex2 = i;
                            break;
                        }
                    }
                    string strLen = encode.GetString(bbs,dataIndex, dataIndex2 - dataIndex);
                    length = int.Parse(strLen, System.Globalization.NumberStyles.AllowHexSpecifier);
                    dataIndex = dataIndex2 + 2;
                }
                byte [] data = new byte[bbs.Length - dataIndex];
                for (int i = dataIndex, j = 0; i < bbs.Length; i++, j++)
                {
                    data[j] = bbs[i];
                }
                if (!dicHeaders.ContainsKey("Content-Length"))
                {
                    data = ClearTail(data);
                }
                return data;
            }
            catch (Exception err)
            {
                throw new Exception(err.Message + "url:" + UrlString);
                throw err;
            }
            finally
            {
                if (clientSocket != null)
                {
                    try
                    {
                        clientSocket.Close();
                    }
                    catch
                    {

                    }
                }
            }
        }

        byte[] ClearTail(byte [] data)
        {
                int index = 0;
                for (int i = data.Length-1; i >=0; i--)
                {
                    if (data[i] == '0') 
                    {
                        index = i;
                        break;
                    }
                }
                byte[] data2 = new byte[index];
                Array.Copy(data, data2, index);
                return data2;
        }

        Dictionary<string, string> GetHeaders(string strHeaders)
        {
            var  headers= strHeaders.Split(new string[] { "\r\n"}, StringSplitOptions.RemoveEmptyEntries);
            Dictionary<string, string> dic = new Dictionary<string, string>();
            for (int i = 0; i < headers.Length; i++)
            {
                var c=headers[i];
                if (i == 0)
                {
                    int index = c.IndexOf(" ");
                    dic.Add(c.Substring(0,index),c.Substring(index+1,c.Length-index-1));
                }
                else
                {
                      var temps = c.Split(new string []{": "}, StringSplitOptions.RemoveEmptyEntries);
                      if (!dic.ContainsKey(temps[0]))
                      {
                          dic.Add(temps[0], temps[1]);
                      }
                }
            }
            return dic;
        }


        

        void AddByte(List<byte> lst, byte[] data, int count)
        {
            for (int i = 0; i < count; i++)
            {
                lst.Add(data[i]);
            }
        }
    }
}